[System.CodeDom.Compiler.GeneratedCode("NSwag", "{{ ToolchainVersion }}")]
{{ ClientClassAccessModifier }} partial class {{ Class }} {% if HasBaseType %}: {% endif %}{% if HasBaseClass %}{{ BaseClass }}{% if GenerateClientInterfaces %}, {% endif %}{% endif %}{% if GenerateClientInterfaces %}I{{ Class }}{% endif %}
{
{% if UseBaseUrl and GenerateBaseUrlProperty -%}
    private string _baseUrl = "{{ BaseUrl }}";
{% endif -%}
{% if InjectHttpClient -%}
    private {{ HttpClientType }} _httpClient;
{% endif -%}
{% if UseRequestAndResponseSerializationSettings -%}
    private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _requestSettings;
    private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _responseSettings;
{% else -%}
    private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
{% endif -%}

{% if HasConfigurationClass -%}
    public {{ Class }}({{ ConfigurationClass }} configuration{% if InjectHttpClient %}, {{ HttpClientType }} httpClient{% endif %}) : base(configuration)
    {
{%     if InjectHttpClient -%}
        _httpClient = httpClient; 
{%     endif -%}
{% elseif UseBaseUrl and HasBaseUrl == false -%}
    public {{ Class }}(string baseUrl{% if InjectHttpClient -%}, {{ HttpClientType }} httpClient{% endif %})
    {
        BaseUrl = baseUrl; 
{%     if InjectHttpClient -%}
        _httpClient = httpClient; 
{%     endif -%}
{% elseif InjectHttpClient -%}
    public {{ Class }}({{ HttpClientType }} httpClient)
    {
        _httpClient = httpClient; 
{% else -%}
    public {{ Class }}()
    {
{% endif -%}
{% if UseRequestAndResponseSerializationSettings -%}
        _requestSettings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() => CreateSerializerSettings(true));
        _responseSettings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() => CreateSerializerSettings(false));
{% else -%}
        _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
{% endif -%}
        {% template Client.Class.Constructor %}
    }

    private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings({% if UseRequestAndResponseSerializationSettings %}bool isRequest{% endif %})
    {
        var settings = {{ JsonSerializerParameterCode }};
{% if SerializeTypeInformation -%}
        settings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
{% endif -%}
        UpdateJsonSerializerSettings(settings{% if UseRequestAndResponseSerializationSettings %}, isRequest{% endif %});
        return settings;
    }

{% if UseBaseUrl and GenerateBaseUrlProperty -%}
    public string BaseUrl 
    {
        get { return _baseUrl; }
        set { _baseUrl = value; }
    }

{% endif -%}
{% if ExposeJsonSerializerSettings %}
{%     assign serializerSettingsAccessModifier = "public" -%}
{% else -%}
{%     assign serializerSettingsAccessModifier = "protected" -%}
{% endif -%}
{% if UseRequestAndResponseSerializationSettings -%}
    {{ serializerSettingsAccessModifier }} Newtonsoft.Json.JsonSerializerSettings RequestJsonSerializerSettings { get { return _requestSettings.Value; } }
    {{ serializerSettingsAccessModifier }} Newtonsoft.Json.JsonSerializerSettings ResponseJsonSerializerSettings { get { return _responseSettings.Value; } }
{% else -%}
    {{ serializerSettingsAccessModifier }} Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
{% endif -%}

{% if GenerateUpdateJsonSerializerSettingsMethod -%}
{%     if UseRequestAndResponseSerializationSettings -%}
    partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings, bool isRequest);
{%     else -%}
    partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
{%     endif -%}
{% endif -%}
    partial void PrepareRequest({{ HttpClientType }} client, System.Net.Http.HttpRequestMessage request, string url);
    partial void PrepareRequest({{ HttpClientType }} client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
    partial void ProcessResponse({{ HttpClientType }} client, System.Net.Http.HttpResponseMessage response);

{% for operation in Operations -%}
{%     if GenerateOptionalParameters == false -%}
    {% template Client.Method.Documentation %}
    {% template Client.Method.Annotations %}
    {{ operation.MethodAccessModifier }} {{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
    {
        return {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None);
    }

{%     endif -%}
{%     if GenerateSyncMethods -%}
    {% template Client.Method.Documentation %}
    {% template Client.Method.Annotations %}
    {{ operation.MethodAccessModifier }} {{ operation.SyncResultType }} {{ operation.ActualOperationName }}({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}{% if parameter.IsLast == false %}, {% endif %}{% endfor %})
    {
        {% if operation.HasResult or operation.WrapResponse %}return {% endif %}System.Threading.Tasks.Task.Run(async () => await {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.VariableName }}, {% endfor %}System.Threading.CancellationToken.None)).GetAwaiter().GetResult();
    }

{%     endif -%}
    /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
    {% template Client.Method.Documentation %}
    {% template Client.Method.Annotations %}
    {{ operation.MethodAccessModifier }} async {{ operation.ResultType }} {{ operation.ActualOperationName }}Async({% for parameter in operation.Parameters %}{{ parameter.Type }} {{ parameter.VariableName }}{% if GenerateOptionalParameters and parameter.IsOptional %} = null{% endif %}, {% endfor %}System.Threading.CancellationToken cancellationToken{% if GenerateOptionalParameters %} = default(System.Threading.CancellationToken){% endif %})
    {
{%     for parameter in operation.PathParameters -%}
{%         if parameter.IsNullable == false and parameter.IsRequired -%}
        if ({{ parameter.VariableName }} == null)
            throw new System.ArgumentNullException("{{ parameter.VariableName }}");

{%         endif -%}
{%     endfor -%}
{%     for parameter in operation.QueryParameters -%}
{%         if parameter.IsNullable == false and parameter.IsRequired -%}
        if ({{ parameter.VariableName }} == null)
            throw new System.ArgumentNullException("{{ parameter.VariableName }}");

{%         endif -%}
{%     endfor -%}
{%     if operation.HasContent and operation.ContentParameter.IsRequired -%}
        if ({{ operation.ContentParameter.VariableName }} == null)
            throw new System.ArgumentNullException("{{ operation.ContentParameter.VariableName }}");

{%     endif -%}
        var urlBuilder_ = new System.Text.StringBuilder();
        urlBuilder_.Append({% if UseBaseUrl %}BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/{% else %}"{% endif %}{{ operation.Path }}{% if operation.HasQueryParameters %}?{% endif %}");
{%     for parameter in operation.PathParameters -%}
{%         if parameter.IsOptional -%}
        if ({{ parameter.VariableName }} != null)
            {% template Client.Class.PathParameter %}
        else
            urlBuilder_.Replace("/{{ "{" }}{{ parameter.Name }}}", string.Empty);
{%         else -%}
        {% template Client.Class.PathParameter %}
{%         endif -%}
{%     endfor -%}
{%     for parameter in operation.QueryParameters -%}
{%         if parameter.IsOptional -%}
        if ({{ parameter.VariableName }} != null) 
        {
            {% template Client.Class.QueryParameter %}
        }
{%         else -%}
        {% template Client.Class.QueryParameter %}
{%         endif -%}
{%     endfor -%}
{%     if operation.HasQueryParameters -%}
        urlBuilder_.Length--;
{%     endif -%}

{%     if InjectHttpClient -%}
        var client_ = _httpClient;
{%     elseif UseHttpClientCreationMethod -%}
        var client_ = await CreateHttpClientAsync(cancellationToken).ConfigureAwait(false);
{%     else -%}
        var client_ = new {{ HttpClientType }}();
{%     endif -%}
{%     if InjectHttpClient == false and DisposeHttpClient -%}
        var disposeClient_ = true;
{%     else -%}
        var disposeClient_ = false;
{%     endif -%}
        try
        {
{%     if UseHttpRequestMessageCreationMethod -%}
            using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false))
{%     else -%}
            using (var request_ = new System.Net.Http.HttpRequestMessage())
{%     endif -%}
            {
{%     for parameter in operation.HeaderParameters -%}
{%         if parameter.IsRequired -%}
                if ({{ parameter.VariableName }} == null)
                    throw new System.ArgumentNullException("{{ parameter.VariableName }}");
                {% template Client.Class.HeaderParameter %}
{%         else -%}
                if ({{ parameter.VariableName }} != null)
                    {% template Client.Class.HeaderParameter %}
{%         endif -%}
{%     endfor -%}
{%     if operation.HasContent -%}
{%         if operation.HasBinaryBodyParameter -%}
{%             if operation.ContentParameter.HasBinaryBodyWithMultipleMimeTypes -%}
                var content_ = new System.Net.Http.StreamContent({{ operation.ContentParameter.VariableName }}.Data);
                content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse({{ operation.ContentParameter.VariableName }}.ContentType);
{%             else -%}
                var content_ = new System.Net.Http.StreamContent({{ operation.ContentParameter.VariableName }});
                content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("{{ operation.Consumes }}");
{%             endif -%}
{%         elseif operation.HasXmlBodyParameter -%}
                var content_ = new System.Net.Http.StringContent({{ operation.ContentParameter.VariableName }});
                content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("{{ operation.Consumes }}");
{%         else -%}
                var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject({{ operation.ContentParameter.VariableName }}, {% if SerializeTypeInformation %}typeof({{ operation.ContentParameter.Type }}), {% endif %}{% if UseRequestAndResponseSerializationSettings %}_requestSettings{% else %}_settings{% endif %}.Value));
                content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("{{ operation.Consumes }}");
{%         endif -%}
                request_.Content = content_;
{%     else -%}
{%         if operation.HasFormParameters -%}
{%             if operation.ConsumesFormUrlEncoded -%}
                var keyValues_ = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>();
{%                 for parameter in operation.FormParameters -%}
{%                     if parameter.IsNullable -%}
                if ({{ parameter.VariableName }} != null)
{%                     else -%}
                if ({{ parameter.VariableName }} == null)
                    throw new System.ArgumentNullException("{{ parameter.VariableName }}");
                else
{%                     endif -%}
                    keyValues_.Add(new System.Collections.Generic.KeyValuePair<string, string>("{{ parameter.Name }}", ConvertToString({{ parameter.VariableName }}, System.Globalization.CultureInfo.InvariantCulture)));
{%                 endfor -%}
                request_.Content = new System.Net.Http.FormUrlEncodedContent(keyValues_);
{%             else -%}
                var boundary_ = System.Guid.NewGuid().ToString();
                var content_ = new System.Net.Http.MultipartFormDataContent(boundary_);
                content_.Headers.Remove("Content-Type");
                content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_);
{%                 for parameter in operation.FormParameters -%}
{%                     if parameter.IsNullable -%}
                if ({{ parameter.VariableName }} != null)
{%                     else -%}
                if ({{ parameter.VariableName }} == null)
                    throw new System.ArgumentNullException("{{ parameter.VariableName }}");
                else
{%                     endif -%}
                {
{%                     if parameter.IsFile -%}
{%                         if parameter.IsArray -%}
                    foreach (var item_ in {{ parameter.VariableName }})
                    {
                        var content_{{ parameter.VariableName }}_ = new System.Net.Http.StreamContent(item_.Data);
                        if (!string.IsNullOrEmpty(item_.ContentType))
                            content_{{ parameter.VariableName }}_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(item_.ContentType);
                        content_.Add(content_{{ parameter.VariableName }}_, "{{ parameter.Name }}", item_.FileName ?? "{{ parameter.Name }}");
                    }
{%                         else -%}
                    var content_{{ parameter.VariableName }}_ = new System.Net.Http.StreamContent({{ parameter.VariableName }}.Data);
                    if (!string.IsNullOrEmpty({{ parameter.VariableName }}.ContentType))
                        content_{{ parameter.VariableName }}_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse({{ parameter.VariableName }}.ContentType);
                    content_.Add(content_{{ parameter.VariableName }}_, "{{ parameter.Name }}", {{ parameter.VariableName }}.FileName ?? "{{ parameter.Name }}");
{%                         endif -%}
{%                     else -%}
                    content_.Add(new System.Net.Http.StringContent(ConvertToString({{ parameter.VariableName }}, System.Globalization.CultureInfo.InvariantCulture)), "{{ parameter.Name }}");
{%                     endif -%}
                }
{%                 endfor -%}
                request_.Content = content_;
{%             endif -%}
{%         elseif operation.IsGetOrDeleteOrHead == false -%}
                request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "{{ operation.Produces }}");
{%         endif -%}
{%     endif -%}
                request_.Method = new System.Net.Http.HttpMethod("{{ operation.HttpMethodUpper | upcase }}");
{%     if operation.HasResultType and operation.HasAcceptHeaderParameterParameter == false -%}
                request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("{{ operation.Produces }}"));
{%     endif -%}

                PrepareRequest(client_, request_, urlBuilder_);
                var url_ = urlBuilder_.ToString();
                request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
                PrepareRequest(client_, request_, url_);

                {% template Client.Class.BeforeSend %}
                var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
                var disposeResponse_ = true;
                try
                {
                    var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
                    if (response_.Content != null && response_.Content.Headers != null)
                    {
                        foreach (var item_ in response_.Content.Headers)
                            headers_[item_.Key] = item_.Value;
                    }

                    ProcessResponse(client_, response_);

                    var status_ = (int)response_.StatusCode;
{%     for response in operation.Responses -%}
                    if (status_ == {{ response.StatusCode }}{% if response.CheckChunkedStatusCode %} || status_ == 206{% endif %})
                    {
                        {% template Client.Class.ProcessResponse %}
                    }
                    else
{%     endfor -%}
{%     if operation.HasDefaultResponse -%}
{%         if operation.DefaultResponse.HasType -%}
                    {
{%             assign response = operation.DefaultResponse -%}
                        {% template Client.Class.ProcessResponse %}
                    }
{%         elseif operation.HasSuccessResponse -%}
                    {
                        var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 
                        throw new {{ ExceptionClass }}("{{ operation.DefaultResponse.ExceptionDescription }}", status_, responseData_, headers_, null);
                    }
{%        elseif operation.HasResultType -%}
{%             if operation.WrapResponse and operation.UnwrappedResultType != "FileResponse" -%}
                    return new {{ ResponseClass }}<{{ operation.UnwrappedResultType }}>(status_, headers_, {{ operation.UnwrappedResultDefaultValue }}); 
{%             else -%}
                    return {{ operation.UnwrappedResultDefaultValue }};
{%             endif -%}
{%         elseif operation.WrapResponse -%}
                    return new {{ ResponseClass }}(status_, headers_); 
{%         endif -%}
{%     else -%}
{%         if operation.HasSuccessResponse == false -%}
{% comment %} 
    If the success response has already been explicitely declared, there is no need for this default code (because handled above).
    Otherwise, return default values on success because we don't want to throw on "unknown status code".
    Success is always expected
{% endcomment -%}
                    if (status_ == 200 || status_ == 204)
                    {
{%             if operation.HasResultType -%}
{%                 if operation.WrapResponse and operation.UnwrappedResultType != "FileResponse" -%}
                        return new {{ ResponseClass }}<{{ operation.UnwrappedResultType }}>(status_, headers_, {{ operation.UnwrappedResultDefaultValue }}); 
{%                 else -%}
                        return {{ operation.UnwrappedResultDefaultValue }};
{%                 endif -%}
{%             elseif operation.WrapResponse -%}
                        return new {{ ResponseClass }}(status_, headers_); 
{%             else -%}{% comment %} This method isn't expected to return a value. Just return. {% endcomment -%}
                        return;
{%             endif -%}
                    }
                    else
{%         endif -%}
                    {
                        var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); 
                        throw new {{ ExceptionClass }}("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
                    }
{%     endif -%}
                }
                finally
                {
                    if (disposeResponse_)
                        response_.Dispose();
                }
            }
        }
        finally
        {
            if (disposeClient_)
                client_.Dispose();
        }
    }

{% endfor -%}
    protected struct ObjectResponseResult<T>
    {
        public ObjectResponseResult(T responseObject, string responseText)
        {
            this.Object = responseObject;
            this.Text = responseText;
        }

        public T Object { get; }

        public string Text { get; }
    }

    {% template Client.Class.ReadObjectResponse %}

    {% template Client.Class.ConvertToString %}
    {% template Client.Class.Body %}
}
